#include "ParseBaseNodes.h"
#include "NodeVisitor.h"

using namespace std;

/* PARSE NODE */
ParseNode::ParseNode() : parent(0x0) {}
ParseNode::~ParseNode() { }
ParentNode* ParseNode::SetType(string name, ParentNode *p) {
	static map<string, ParseNode*>::const_iterator end = _typeMapping.end();

	map<string, ParseNode*>::const_iterator type = _typeMapping.find(name);
	if (type == end) return p;

	ParentNode *result = type->second->Convert(p);
	if (result != p) {
		delete p;
		//Update the children
		for (vector<SP<ParseNode> >::iterator it = result->children.begin(); it < result->children.end(); ++it) (**it).parent = result;
	}
	return result;
}
ParseNode* ParseNode::SetType(string name, LeafNode *n) {
	static map<string, ParseNode*>::const_iterator end = _typeMapping.end();

	map<string, ParseNode*>::const_iterator type = _typeMapping.find(name);
	if (type == end) return n;

	ParseNode *result = type->second->Convert(n);
	delete n;
	return result;
}

/* PARENT NODE */
ParentNode::ParentNode() {}
ParentNode::ParentNode(unsigned int size) : children(vector<SP<ParseNode> >(size)) {}
ParentNode::~ParentNode() {}

void ParentNode::Accept(NodeVisitor *v) {
	if (v->traverseType & NodeVisitor::Pre) { v->current_traverse = NodeVisitor::Pre; CascadeAccept(v); }
	if (v->Break()) return;
	v->visit(this);
	if (v->Break()) return;
	if (v->traverseType & NodeVisitor::Post) { v->current_traverse = NodeVisitor::Post; CascadeAccept(v); }
}

void ParentNode::CascadeAccept(NodeVisitor *v) {

	//Ask each child to accept the visitor first
	if (children.empty()) return;
	//Some more useless nodes have a habit of dying while their children are processing. Force them to stay alive
	SP<ParseNode> keep_me_alive = this;
	for (unsigned int i = 0; i < children.size(); ++i) {
		//Sometimes a child might change us. So remember what the child was
		SP<ParseNode> n = children[i]();
		n()->Accept(v);
		//And if it's a different child, back up so we can run over it
		if (children.size() > i && n() != children[i]()) --i;
	}
}

vector<SP<ParseNode> >::iterator ParentNode::FindChild(string id) {
	vector<SP<ParseNode> >::iterator elem = children.begin(), end = children.end();
	for (; elem != end; ++elem) if ((**elem).Type() == id) break;
	return elem;
}
void ParentNode::DeleteChildren() {
	children.clear();
}
void ParentNode::DeleteLeafs() {
	for (vector<SP<ParseNode> >::iterator it = children.begin(); it < children.end();) {
		if (!(**it).IsParent()) {
			it = children.erase(it);
		} else ++it;
	}
}
void ParentNode::DeleteOfType(string type) {
	for (vector<SP<ParseNode> >::iterator it = children.begin(); it < children.end();) {
		if ((**it).Type() == type) {
			it = children.erase(it);
		} else ++it;
	}
}
void FlattenOn(string type, vector<SP<ParseNode> > &expansion, vector<SP<ParseNode> > &children, bool remove = true) {
	for (vector<SP<ParseNode> >::iterator it = children.begin(); it != children.end(); ++it) {
		if ((*it)() && (**it).Type() == type) {
			if( (**it).IsParent()) FlattenOn(type, expansion, ((ParentNode*)(*it)())->children);
		} else expansion.push_back(*it);
	}
}
void ParentNode::FlattenOn(string type, bool remove) {
	//Generic flatten
	vector<SP<ParseNode> > newchildren;
	::FlattenOn(type, newchildren, children, remove);
	children = newchildren;
	//Make sure they all point to the correct place
	for (vector<SP<ParseNode> >::iterator it = children.begin(); it != children.end(); ++it) (**it).parent = this;
}
bool ParentNode::HasChildOfType(string type) {
	return (*this)[type] != 0x0;
}

void ParentNode::ReplaceMeWith(ParseNode *n) {
	vector<SP<ParseNode> >::iterator self;
	for (self = parent->children.begin(); self != parent->children.end() && (*self)() != this; ++self);

	if (self == parent->children.end()) return;

	n->parent = parent;
	*self = n;
}

SP<ParseNode> &ParentNode::operator[] (unsigned int i) { 
	return children[i]; 
}
ParseNode *ParentNode::operator[] (string s) {
	vector<SP<ParseNode> >::iterator it = FindChild(s);
	return it != children.end() ? (*it)() : 0x0; //The null
}

/* LEAF NODE */
LeafNode::LeafNode(string type, string lexeme) : type(type), lexeme(lexeme) {}
void LeafNode::Accept(NodeVisitor *v) { v->visit(this); }

/* DECLARATION NODE */

void DeclarationNode::SetIdentifier() {

	vector<SP<ParseNode> >::iterator name = FindChild("Name");
	
	if (name == children.end()){
		//cout << children.size() << endl;
		//for(vector<SP<ParseNode> >::iterator it = children.begin(); it < children.end(); ++it) cout << (**it).Type() << endl;
		
		identifier = ((LeafNode*)(*this)["identifier"])->lexeme;
		//cout << identifier << endl;
	} else {
		identifier = string();
		for (vector<SP<ParseNode> >::iterator it = ((ParentNode*)(*name)())->children.begin(); it < ((ParentNode*)(*name)())->children.end(); ++it) {
			identifier.append(((LeafNode*)(*it)())->lexeme+'.');
		}
		children.erase(name);
	}

}

/* MODIFIED NODE */
void ModifiedNode::CollectModifiers() {
	ParentNode *mods = (ParentNode*)(*this)["Modifiers"];
	for (vector<SP<ParseNode> >::iterator it = mods->children.begin(); it < mods->children.end(); ++it) {
		if ((**it).Type() == "public") access += Public;
		else if ((**it).Type() == "protected") access += Protected;
		else if ((**it).Type() == "abstract") modifier += Abstract;
		else if ((**it).Type() == "final") modifier += Final;
		else if ((**it).Type() == "static") modifier += Static;
		else if ((**it).Type() == "native") modifier += Native;
	}

	mods->DeleteLeafs();
}

bool ModifiedNode::CheckModifiers(unsigned char a, unsigned char m) {
	if (!(access == Public || access == Protected)) return false;
	if ((modifier & Abstract && (modifier & Final || modifier & Static)) || (modifier & Final && modifier & Static)) return false;
	if (modifier & Native && !(modifier & Static)) return false;
	return !((access & a) != access || (modifier & m) != modifier);
}

/* TYPED NODE */

void TypedNode::FillType() {
	GetTypeCategory();
	GetTypeNameComponents();

	DeleteOfType("Type");
}

void TypedNode::GetTypeCategory() {
	unsigned int cat = 0x0;


	TypeNode *type = (TypeNode*)(*this)["Type"];
	if (!type) cat = TypeMeta::Void;
	else {

		if (type->isArray) cat |= TypeMeta::Array;

		//Strip out if it's a primitive type
		ParseNode *typenamenode = (*type)[0]();
		switch (typenamenode->Type()[0]) {
			case 'b':
				if (typenamenode->Type() == "boolean") cat |= TypeMeta::Boolean;
				else cat |= TypeMeta::Byte;
				break;
			case 'c':
				cat |= TypeMeta::Char;
				break;
			case 's':
				cat |= TypeMeta::Short;
				break;
			case 'i':
				cat |= TypeMeta::Int;
				break;
			default:
				cat |= TypeMeta::Reference;
		}

	}
	type_meta.category = (TypeMeta::TypeCategory) cat;

	type_meta.reference = 0x0;
}

void TypedNode::GetTypeNameComponents() {
	type_package_name = string();
	type_name = string();

	TypeNode *type = (TypeNode*)(*this)["Type"];
	if (!type) { type_name = "void"; return; }
	NameNode *name = (NameNode*)(*type)[0]();

	//Opps. It's actually just a leaf node
	if (!name->IsParent()) {
		type_name = ((LeafNode*)name)->lexeme;
	} else {
		for (vector<SP<ParseNode> >::iterator it = name->children.begin(); it < name->children.end() - 1; ++it)
			type_package_name.append(((LeafNode*)(*it)())->lexeme + '.');

		type_name = ((LeafNode*)name->children.back()())->lexeme;
	}
}